package org.moonholder.springboot.damocles.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.moonholder.springboot.damocles.config.SessionManage;
import org.moonholder.springboot.damocles.entity.Authority;
import org.moonholder.springboot.damocles.entity.User;
import org.moonholder.springboot.damocles.service.IAuthorityService;
import org.moonholder.springboot.damocles.service.IUserService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service("userDetailService")
public class CustomUserDetailService implements UserDetailsService {

    @Resource
    private IAuthorityService authorityService;
    @Resource
    private IUserService userService;
    @Resource
    private SessionManage sessionManage;

    @Override
    @Cacheable(value = "user", key = "#username")
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.getOne(new QueryWrapper<User>().eq(StringUtils.hasLength(username), "username", username));
        Assert.notNull(user, "没有相关用户信息");
        List<Authority> authorities = authorityService.findAuthorityByUsername(username);
        user.setAuthorities(authorities);
        return user;
    }

    /**
     * 刷新session
     * 刷新在线用户角色
     * @param user
     */
    private void refreshSession(User user) {
//        UserSessionManage userSessionManage = sessionManage.getUserSessionManage();
//        List<HttpSession> userSession = userSessionManage.getUserSession(user.getId().toString());
//        userSession.forEach(this::reloadUserAuthority);
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        List<Authority> updatedAuthorities = new ArrayList<>();
        Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(), updatedAuthorities);
        SecurityContextHolder.getContext().setAuthentication(newAuth);
    }

    /**
     * 重新加载用户的权限
     *
     * @param session
     */
    public void reloadUserAuthority(HttpSession session) {
        try {
            SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
            Authentication authentication = securityContext.getAuthentication();
            Object principal1 = authentication.getPrincipal();
            if (principal1 instanceof User) {
                UserDetails principal = (User) principal1;
                /**
                 * 重载用户对象
                 */
                principal = this.loadUserByUsername(principal.getUsername());
                // 重新new一个token，因为Authentication中的权限是不可变的.
                UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
                        principal, authentication.getCredentials(),
                        principal.getAuthorities());
                result.setDetails(authentication.getDetails());
                securityContext.setAuthentication(result);
            }
        } catch (Exception e) {
            log.error("当前用户session有可能不存在");
        }
    }

}
